home *** CD-ROM | disk | FTP | other *** search
- //===========================================================================
- // GETILBM.C -- for AmigaDOS 2.0/3.0 (and maybe 1.3 with iffparse.library)
- // Rev: 30 September 1994, Alex Matulich matulich_alex@SEAA.NAVSEA.NAVY.MIL
- //
- // For SAS C/C++ 6.xx. Compile with IGNORE=51 to disable warnings for
- // C++ comments (I got addicted to those C++ comments...)
- //
- // This module is for loading IFF ILBM pictures. The *only* functions you
- // need to call are loadilbmScreen() and freeilbmScreen(), or if you are
- // just loading into bitmaps, call loadilbmBitMap() and freeBitMap().
- //
- // The iffparse.library must be opened prior to calling these routines.
- // SAS C 6.xx does this automatically for you.
- //
- // This module was adapted from the confusing plethora of functions in the
- // Amiga Developer's package for AmigaDOS 3.1. All adaptations and excerpts
- // are indicated in the comments.
- //===========================================================================
-
-
- //---------------------------------------------------------------------------
- // To make the demo ILBM file reader, compile with only the symbol DEMO
- // defined. Example: sc optimize optsize def=DEMO link getilbm.c
- //
- // You might have your own versions of getBitMap() and freeBitMap() external
- // to this module (I do, for example, in my video buffering module). If so,
- // then make sure the following two #defines are commented out. If you wish
- // to use the getBitMap() and freeBitMap() functions contained in this
- // module, then uncomment the following two #defines.
-
- // #define USE_GETBM // comment out if you already have a getBitMap()
- // #define USE_FREEBM // comment out if you already have a freeBitMap()
-
- // These functions, if external, should be compatible with the prototypes
- // in getilbm_proto.h.
- //
- // Defining TIMECHECK enables calls to a user-supplied external function
- // check_for_switch() while the IFF file is loading. The purpose of this
- // function is to allow the program to do time-critical things while a
- // large ILBM file is loading. Sort of a pseudo-multitasking technique.
-
- // #define TIMECHECK // only if you need a check_for_switch() function
-
- // Often it is more useful to simply load an IFF file into a bitmap, rather
- // than create a whole screen for it. If you want to do just this, and you
- // never need to load an IFF file into a screen, then uncomment this line:
-
- // #define NOILBMSCREEN // only compile loadilbmBitMap() and associates
-
- // This will cause the functions loadilbmScreen() and associated functions
- // and declarations to be skipped during compililation.
- //
- // Conversely, if you don't need loadilbmBitMap(), but only loadilbmScreen(),
- // then uncomment this line:
- //
- // #define ILBMSCREENONLY // only compile loadilbmScreen() and associates
- //
- // The existence of getBitMap() and freeBitMap() are still controlled by
- // USE_GETBM and USE_FREEBM.
- // Do not define both NOILBMSCREEN and ILBMSCREENONLY at the same time.
- // Do not define either of them if you need *both* loadilbmScreen() and
- // loadilbmBitMap().
- //---------------------------------------------------------------------------
-
- #ifdef NOTIMECHECK // for compatibility with previous versions
- #undef TIMECHECK
- #endif
-
- #ifdef DEMO // re-set definitions if compiling the demo
- #ifdef USE_GETBM
- #undef USE_GETBM // demo doesn't need getBitMap()
- #endif
- #ifdef USE_FREEBM
- #undef USE_FREEBM // demo doesn't need freeBitMap()
- #endif
- #ifdef TIMECHECK
- #undef TIMECHECK // demo doesn't need check_for_switch()
- #endif
- #ifdef NOILBMSCREEN
- #undef NOILBMSCREEN // demo doesn't need loadilbmBitmap()
- #endif
- #ifndef ILBMSCREENONLY
- #define ILBMSCREENONLY // demo DOES need loadilbmScreen()
- #endif
- #endif
-
- #include <exec/memory.h>
- #include <exec/libraries.h>
- #include <graphics/gfx.h>
- #include <libraries/dos.h>
- #include <libraries/iffparse.h>
-
- #include <proto/exec.h>
- #include <proto/graphics.h>
- #include <proto/dos.h>
- #include <proto/iffparse.h>
-
- #ifndef NOILBMSCREEN
- #define USE_BUILTIN_MATH 1 // to use built-in min() and max() in string.h
- #include <string.h>
- #include <graphics/display.h>
- #include <intuition/intuition.h>
- #include <proto/intuition.h>
- #endif // !NOILBMSCREEN
-
- #include <stdlib.h>
-
- #include "getilbm_proto.h" // prototypes for user-callable functions
-
- extern struct Library *IFFParseBase;
-
-
- // definitions from iffp/iff.h
-
- #define ChunkMoreBytes(cn) (cn->cn_Size - cn->cn_Scan)
-
- struct Chunk {
- struct Chunk *ch_Next;
- long ch_Type, ch_ID, ch_Size;
- void *ch_Data;
- };
-
-
- // definitions from iffp/ilbm.h
-
- #define ID_ILBM MAKE_ID('I','L','B','M')
- #define ID_BMHD MAKE_ID('B','M','H','D')
- #define ID_CMAP MAKE_ID('C','M','A','P')
- #define ID_BODY MAKE_ID('B','O','D','Y')
- #define ID_CAMG MAKE_ID('C','A','M','G')
-
- // sizeof(a 3-byte structure) returns 16 due to word alignment, so we use:
- #define sizeofColorRegister 3
-
- #define MAXAMDEPTH 8 // used for OS<V37, screen.c maxdisplaydepth(ID)
- #define MAXAMCOLORREG 32 // should use ViewPort->ColorMap.Count instead
-
- #define RowBytes(w) ((((w) + 15) >> 4) << 1)
- #define RowBits(w) ((((w) + 15) >> 4) << 4)
-
- #define mskNone 0 // masking techniques
- #define mskHasMask 1
- #define cmpNone 0 // compression techniques
- #define cmpByteRun1 1
-
- typedef struct {
- UWORD w, h; // raster width and height
- WORD x, y; // pixel position for this image
- UBYTE nPlanes, masking, // # source bitplanes, masking (?)
- compression, flags; // compression, Commodore-defined flags
- UWORD transparentColor; // transparent color number (sort of)
- UBYTE xAspect, yAspect; // pixel aspect ratio width/height
- WORD pageWidth, pageHeight; // source page size in pixels
- } BitMapHeader;
-
- typedef struct { UBYTE red, green, blue; } ColorRegister;
- typedef struct { ULONG ViewModes; } CamgChunk;
-
- #define BMHDB_CMAPOK 7
- #define BMHDF_CMAPOK (1 << BMHDB_CMAPOK)
-
-
- // from iffp/packer.h
- #define MaxPackedSize(rowsize) ((rowsize)+(((rowsize)+127)>>7))
-
-
- //---------------------------------------------------------------------------
- // Skip following five declarations if you don't need loadilbmScreen().
-
- #ifndef NOILBMSCREEN
-
- static UWORD __far ins_pens[] = { 0xffff }; // minimal pen definitions
-
- long li_errcode; // error code returned by OpenScreen()
-
- // You will want to expand the following tag list if you decide to
- // substitute OpenScreenTagList() for OpenScreen() in loadilbmScreen().
- // OpenScreen() works with all video modes, and is used here for
- // compatibility with AmigaDOS 1.3, just in case such an OS happens to
- // have a compatible iffparse.library.
-
- static struct TagItem __far ins_ext[] = {
- SA_DisplayID, 0L, // tag needed for display mode
- SA_DClip, 0L, // needed for screen centering
- SA_AutoScroll, TRUE, // not really needed, but who cares?
- SA_Pens, (ULONG)ins_pens, // minimal tags needed for 2.0
- SA_ErrorCode, (ULONG)&li_errcode, // examine li_errcode for error codes
- TAG_DONE
- };
-
- // Instead of opening a screen with functions specific to AmigaDOS 2.0,
- // we define an ExtNewScreen structure for use with OpenScreen() to
- // maintain compatibility with earlier OS versions. The ins_ext[] taglist
- // above provides the enhancements necessary for OS 2.0 or greater.
-
- static struct ExtNewScreen __far ins = {
- 0, 0, ~0, ~0, // left, top, width & height
- 2, 0, 1, // depth, DetailPen, BlockPen
- 0, // ViewModes
- CUSTOMSCREEN | SCREENQUIET | SCREENBEHIND | NS_EXTENDED,
- NULL, // font
- NULL, NULL, NULL, // title, gadgets, bitmap
- ins_ext // tag extensions
- };
-
- static struct NewWindow __far inw = {
- 0, 0, ~0, ~0, // left, top, width, height
- 0, 1, // DetailPen, BlockPen
- IDCMP_RAWKEY | IDCMP_VANILLAKEY, // IDCMP flags (whatever you like)
- SIMPLE_REFRESH | BORDERLESS | BACKDROP | NOCAREREFRESH,
- NULL, // pointer to 1st user gadget
- NULL, // pointer to user checkmark
- NULL, // title
- NULL, // pointer to window screen
- NULL, // no superbitmap
- 100,100,100,100, // width & height, min & max
- CUSTOMSCREEN
- };
-
- #endif // !NOILBMSCREEN
-
- //---------------------------------------------------------------------------
-
- // internal prototypes
-
- struct IFFHandle *getilbminfo(char *, USHORT *, USHORT *,
- USHORT *, WORD **, USHORT *, unsigned long *, BitMapHeader **);
- void freeIFFHandle(struct IFFHandle *iff);
- int loadbody(struct IFFHandle *, struct BitMap *, BitMapHeader *);
- int loadbody2(struct IFFHandle *, struct BitMap *, BYTE *,
- BitMapHeader *, BYTE *, ULONG);
- BOOL unpackrow(BYTE **pSource, BYTE **pDest, WORD srcBytes0, WORD dstBytes0);
-
-
- #ifdef DEMO
- //===========================================================================
- // DEMO main() FUNCTION
- // For demonstrating loadilbmScreen().
- //===========================================================================
- #include <stdio.h>
-
- int main(int argc, char *argv[])
- {
- struct Screen *s; // pointer to the screen that will be shown
- struct Message *msg; // this is for trapping keystrokes
- int i = 0, err = 0;
-
- if (argc < 2) {
- fputs("ILBM Viewer\nNeeds filenames as commandline arguments.\n", stderr);
- return err;
- }
- fputs("Press any key to finish viewing an image.\n\n", stderr);
-
- while (++i < argc) { // go thru all commandline arguments
- fputs("loading ", stderr); // display the filename being loaded
- fputs(argv[i], stderr);
- fflush(stderr); // make sure the name is displayed
-
- if (s = loadilbmScreen(argv[i])) { // load ILBM file
- ScreenToFront(s); // show it if loaded
- ActivateWindow(s->FirstWindow); // setup for keypress
- Wait(1L<<s->FirstWindow->UserPort->mp_SigBit); // wait for key
- while (msg = GetMsg(s->FirstWindow->UserPort)) // clear msg buffer
- ReplyMsg(msg);
- freeilbmScreen(s, NULL); // close the screen
- fputs("\n", stderr);
- } // go on to next file
-
- else { // or report an error
- fputs("... bad, incompatible, or nonexistent.\n", stderr);
- ++err;
- }
- }
- return err;
- }
- //===========================================================================
- #endif // end of DEMO
-
-
- #ifndef NOILBMSCREEN // ingore next 3 functions if NOILBMSCREEN is defined
-
- //===========================================================================
- // CLIPIT -- called by loadilbmScreen() below
- // Adapted with minor changes from modules/screen.c
- //===========================================================================
- static void clipit(short wide, short high,
- struct Rectangle *spos, struct Rectangle *dclip,
- struct Rectangle *txto, struct Rectangle *stdo,
- struct Rectangle *maxo, struct Rectangle *uclip, BOOL NoCenter)
- {
- struct Rectangle *besto;
- short minx, maxx, miny, maxy,
- txtw, txth, stdw, stdh, bestw, besth;
-
- // get txt, std, and max widths and heights
- txtw = txto->MaxX - txto->MinX + 1;
- txth = txto->MaxY - txto->MinY + 1;
- stdw = stdo->MaxX - stdo->MinX + 1;
- stdh = stdo->MaxY - stdo->MinY + 1;
-
- if (wide <= txtw && high <= txth) {
- besto = txto;
- bestw = txtw;
- besth = txth;
- }
- else {
- besto = stdo;
- bestw = stdw;
- besth = stdh;
- }
-
- if (uclip) {
- *dclip = *uclip;
- spos->MinX = uclip->MinX;
- spos->MinY = uclip->MinY;
- }
- else {
- spos->MinX = minx = besto->MinX - ((wide - bestw) >> 1);
- maxx = wide + minx - 1;
- if (maxx > maxo->MaxX) maxx = maxo->MaxX;
- if (minx < maxo->MinX) {
- minx = maxo->MinX;
- if (NoCenter) spos->MinX = minx;
- }
- miny = besto->MinY - ((high - besth) >> 1);
- spos->MinY = miny = min(miny, txto->MinY);
- maxy = high + miny - 1;
- if (maxy > maxo->MaxY) maxy = maxo->MaxY;
- if (miny < maxo->MinY) {
- miny = maxo->MinY;
- if (NoCenter) spos->MinY = miny;
- }
- dclip->MinX = minx;
- dclip->MinY = miny;
- dclip->MaxX = spos->MaxX = maxx;
- dclip->MaxY = spos->MaxY = maxy;
- }
- }
-
-
- //===========================================================================
- // LOADILBMSCREEN
- // Loads an IFF ILBM file into a bitmap and creates a custom screen to
- // display it, returning a pointer to the screen. The screen is created
- // behind others; use ScreenToFront() to show, and freeilbmScreen() to
- // deallocate the screen. If IFF ILBM file failed to load, NULL is returned
- // and the global long li_errcode is set as defined in <intuition/screens.h>:
- // (0): IFF ILBM file loaded, screen created successfully
- // (1) OSERR_NOMONITOR: Monitor specification unavailable
- // (2) OSERR_NOCHIPS: You need newer custom chips
- // (3) OSERR_NOMEM: Insufficient normal RAM
- // (4) OSERR_NOCHIPMEM: Insufficient chip RAM
- // (5) OSERR_PUBNOTUNIQUE: Public screen name already used
- // (6) OSERR_UNKNOWNMODE: Unrecognized screen mode
- // (7) OSERR_TOODEEP: Too many bitplanes in requested screen
- // (8) OSERR_ATTACHFAIL: Failed to attach screens
- // (9) OSERR_NOTAVAILABLE: Mode unavailable for some other reason
- // other: Unknown error
- //===========================================================================
- struct Screen *loadilbmScreen(char *filename)
- {
- BitMapHeader *bmhd;
- struct Screen *iscr = NULL;
- struct Window *iwnd = NULL;
- USHORT wide, high, deep, colors = MAXAMCOLORREG, err = 0;
- WORD *colortable = NULL;
- unsigned long mode;
- struct Rectangle spos, dclip, txto, stdo, maxo;
- struct IFFHandle *iff = getilbminfo(filename, &wide, &high, &deep,
- &colortable, &colors, &mode, &bmhd);
- if (!iff) return NULL;
- li_errcode = 0;
-
- // The following if() block was adapted from modules/screen.c
- if ( ((struct Library *)GfxBase)->lib_Version >= 36) {
- if (li_errcode = ModeNotAvailable(mode))
- goto lis_done;
- else {
- QueryOverscan(mode, &txto, OSCAN_TEXT);
- QueryOverscan(mode, &stdo, OSCAN_STANDARD);
- QueryOverscan(mode, &maxo, OSCAN_MAX);
- }
- clipit(wide, high, &spos, &dclip, &txto, &stdo, &maxo, NULL, FALSE);
- }
- else spos.MinX = spos.MinY = 0;
-
- ins.LeftEdge = spos.MinX; // these should all go into a taglist if
- ins.TopEdge = spos.MinY; // you decide to substitute
- ins.Width = inw.Width = wide; // OpenScreenTagList() for OpenScreen().
- ins.Height = inw.Height = high;
- ins.Depth = deep;
- ins.ViewModes = 0xffff & (ins.Extension[0].ti_Data = mode);
- ins.Extension[1].ti_Data = (ULONG)&dclip;
- if (iscr = OpenScreen(&ins)) { // You might substitute OpenScreenTagList()
- inw.Width = wide;
- inw.Height = high;
- inw.Screen = iscr;
- if (!(iwnd = OpenWindow(&inw))) {
- err = 1;
- goto lis_done;
- }
- if (err = loadbody(iff, &iscr->BitMap, bmhd)) goto lis_done;
- if (colortable)
- if (((struct Library *)GfxBase)->lib_Version < 39)
- LoadRGB4(&iscr->ViewPort, (UWORD *)colortable, colors);
- else
- LoadRGB32(&iscr->ViewPort, (ULONG *)colortable);
- }
-
- // The error code for extern long li_errcode may be checked here.
- // See getilbm_proto.h for possible values.
-
- lis_done:
- if (err) {
- if (iwnd) CloseWindow(iwnd);
- if (iscr) CloseScreen(iscr);
- iscr = NULL;
- }
- if (colortable) free(colortable);
- freeIFFHandle(iff); // IFF handle must be freed before exiting
- return iscr;
- }
-
-
- //===========================================================================
- // FREEILBMSCREEN
- // Free a screen created by loadilbmScreen(). If you saved the Window's
- // *original* UserPort because you needed to share another one, pass it here,
- // or just pass NULL if the Window still has its original UserPort.
- // This function is not needed if you don't need loadilbmScreen().
- //===========================================================================
- void freeilbmScreen(struct Screen *iscr, struct MsgPort *userport)
- {
- struct Window *fw = iscr->FirstWindow;
- if (fw) {
- struct IntuiMessage *msg;
- if (userport) fw->UserPort = userport;
- while (msg = (struct IntuiMessage *)GetMsg(fw->UserPort))
- ReplyMsg((struct Message *)msg);
- CloseWindow(fw);
- }
- CloseScreen(iscr);
- }
-
- #endif // !NOILBMSCREEN
-
-
- #ifndef ILBMSCREENONLY // ignore next function if ILBMSCREENONLY defined
- //===========================================================================
- // LOADILBMBITMAP
- // Allocate a bitmap and load an ILBM file into it. The size of the bitmap
- // allocated is returned in wide, high, and deep, and function returns a
- // pointer to the bitmap, or NULL in the case of an error. wide, high, and
- // deep should all be pointers to unsigned short variables. These variables
- // will be set to the dimensions of the BitMap when the function returns.
- // Remember to free the bitmap with freeBitMap() when you're done with it.
- //===========================================================================
- struct BitMap
- *loadilbmBitMap(char *filename, USHORT *wide, USHORT *high, USHORT *deep)
- {
- BitMapHeader *bmhd;
- struct BitMap *bitmap;
- struct IFFHandle *iff = getilbminfo(filename, wide, high, deep,
- NULL, NULL, NULL, &bmhd);
- if (!iff) return NULL;
-
- // allocate a bitmap according to the data in the bitmap header
- // and load the ILBM file into the bitmap
-
- if (bitmap = getBitMap(*wide, *high, *deep, 1))
- if (loadbody(iff, bitmap, bmhd)) {
- freeBitMap(bitmap); // load was unsuccessfull
- bitmap = NULL;
- }
- freeIFFHandle(iff); // IFF handle must be freed before exiting
- return bitmap;
- }
- #endif // !ILBMSCREENONLY
-
-
- //===========================================================================
- // GETILBMINFO -- called by loadilbmScreen() and loadilbmBitMap()
- // Return an IFF handle for use with loadbody() to load an ILBM body into
- // a bitmap, and set all the appropriate parameters to their correct values.
- // ALL arguments are pointers. Only colortable, colors, and mode may be
- // passed as NULL. Colormap entries are returned in *colortable (which this
- // function allocates), and number of colors in colors. If <V39, colortable
- // is stored as the old 4-bit-per-gun style, and must be appropriately cast.
- // If colors is returned as 0xffff, then a colormap was not found. If you
- // don't want color info, pass NULL for colors and colortable. Likewise for
- // the parameter video mode. bmhd must point to an uninitialized
- // BitMapHeader, which will have its contents initialized inside this
- // function. The IFFHandle returned must be freed later by the calling
- // function using freeIFFHandle().
- // Upon exit, the parser will be stopped at the beginning of the BODY chunk
- // of the ILBM file, so that loadbody() can work properly.
- //===========================================================================
- struct IFFHandle
- *getilbminfo(char *filename, USHORT *wide, USHORT *high, USHORT *deep,
- WORD **colortable, USHORT *colors, unsigned long *mode, BitMapHeader **bmhd)
- {
- struct StoredProperty *sp;
- struct IFFHandle *iff;
-
- if (!IFFParseBase) return NULL;
-
- // open things
-
- if (!(iff = AllocIFF())) return NULL;
- if (!(iff->iff_Stream = Open(filename, MODE_OLDFILE))) goto iffdone;
- InitIFFasDOS(iff);
- if (OpenIFF(iff, IFFF_READ)) goto iffdone;
- #ifdef TIMECHECK
- check_for_switch();
- #endif
-
- // set up the parser and parse the file
-
- if (PropChunk(iff, ID_ILBM, ID_BMHD)) goto iffdone;
- PropChunk(iff, ID_ILBM, ID_CMAP);
- PropChunk(iff, ID_ILBM, ID_CAMG);
- if (StopChunk(iff, ID_ILBM, ID_BODY)) goto iffdone; // stop at start of body
- if (ParseIFF(iff, IFFPARSE_SCAN)) goto iffdone;
-
- #ifdef TIMECHECK
- check_for_switch();
- #endif
-
- // extract header and determine dimensions
- // From modules/getbitmap.c
-
- if (!(sp = FindProp(iff, ID_ILBM, ID_BMHD))) goto iffdone;
- *bmhd = (BitMapHeader *)sp->sp_Data;
-
- *wide = RowBits((*bmhd)->w);
- *high = (*bmhd)->h;
- *deep = (*bmhd)->nPlanes;
-
- #ifndef NOILBMSCREEN // don't need colormap or mode info for bitmaps
-
- // pull out colormap data that was read in if colors & coloratble was passed
- // Adapted from loadcmap() in modules/ilbmr.c
-
- if (colors) { // get colormap information
- if (sp = FindProp(iff, ID_ILBM, ID_CMAP)) {
- register UBYTE *rgb = sp->sp_Data;
- long r, g, b;
- ULONG ncheck;
- USHORT i, ncolors = *colors = sp->sp_Size / sizeofColorRegister;
-
- if ((ncheck = 1 << (*bmhd)->nPlanes) > ncolors) ncheck = ncolors;
- if (((struct Library *)GfxBase)->lib_Version >= 39) {
-
- // for a moment we visit an adaptation of alloccolortable()
- // in modules/ilbmr.c ....
-
- Color32 *ct;
- UWORD AllShifted = TRUE;
- USHORT nc = max(ncolors, 32);
-
- if (!(*colortable = (WORD *)calloc( (nc*sizeof(Color32)) + (4*sizeof(WORD)), 1)))
- goto errctab;
- ct = (Color32 *)(*colortable + 2);
- **colortable = nc;
-
- // now back to loadcmap() in modules/ilbmr.c ....
-
- i = 0;
- while (ncheck--) {
- ct[i].r = r = *rgb++;
- ct[i].g = g = *rgb++;
- ct[i++].b = b = *rgb++;
- if ((r & 0x0f) || (g & 0x0f) || (b & 0x0f)) AllShifted = FALSE;
- }
- if (AllShifted && ((*bmhd)->flags & BMHDF_CMAPOK)) // shift if 4-bit
- for (i = 0; i < ncolors; i++) {
- ct[i].r |= (ct[i].r >> 4);
- ct[i].g |= (ct[i].g >> 4);
- ct[i].b |= (ct[i].b >> 4);
- }
- for (i = 0; i < ncolors; i++) { // scale to 32 bits
- g = ct[i].r;
- ct[i].r |= ((g << 24) | (g << 16) | (g << 8));
- g = ct[i].g;
- ct[i].g |= ((g << 24) | (g << 16) | (g << 8));
- g = ct[i].b;
- ct[i].b |= ((g << 24) | (g << 16) | (g << 8));
- }
- }
- else if (*colortable = (WORD *)calloc(ncolors, sizeof(WORD))) {
- WORD *ct = *colortable;
- while (ncheck--) {
- r = (*rgb++ & 0xf0) << 4;
- g = *rgb++ & 0xf0;
- b = *rgb++ >> 4;
- *(ct++) = r | g | b;
- }
- }
- else {
- errctab: *colortable = NULL;
- *colors = 0xffff;
- }
- }
- else *colors = 0xffff;
- }
-
- // pull out video mode information that was read in, if mode != NULL
-
- if (mode) {
- DisplayInfoHandle displayhandle;
- struct DimensionInfo dimensioninfo;
- UWORD maxdepth = MAXAMDEPTH;
-
- // next 3 lines adapted from getdisplay() in modules/getdisplay.c
-
- if (RowBytes(*wide) < RowBytes((*bmhd)->pageWidth))
- *wide = (*bmhd)->pageWidth;
- *high = max(*high, (*bmhd)->pageHeight);
-
- // next 5 lines from maxdisplaydepth() in modules/getdisplay.c
-
- if (((struct Library *)GfxBase)->lib_Version >= 37)
- if (displayhandle = FindDisplayInfo(*mode))
- if (GetDisplayInfoData(displayhandle, (UBYTE *)&dimensioninfo,
- sizeof(struct DimensionInfo), DTAG_DIMS, NULL))
- maxdepth = dimensioninfo.MaxDepth;
-
- *deep = min(*deep, maxdepth); // from getdisplay() in modules/getdisplay.c
-
- // Remainder of this if() block Adapted from getcamg() in modules/ilbmr.c
-
- *mode = 0L;
- if (sp = FindProp(iff, ID_ILBM, ID_CAMG)) {
- *mode = (*(unsigned long *)sp->sp_Data);
- // knock bad bits out of old-style 16-bit viewmode CAMGs
- if ((!(*mode & MONITOR_ID_MASK)) ||
- ((*mode & EXTENDED_MODE) && (!(*mode & 0xffff0000))))
- *mode &= (~(EXTENDED_MODE | SPRITES | GENLOCK_AUDIO
- | GENLOCK_VIDEO | VP_HIDE));
- // check for bogus CAMG like DPaintII brushes
- if ((*mode & 0xffff0000) && (!(*mode & 0x00001000))) sp = NULL;
- }
- if (!sp) { // no CAMG or bad CAMG present - use computed modes
- if (*wide >= 640) *mode = HIRES;
- if (*high >= 400) *mode |= LACE;
- if (*deep == 6) *mode |= HAM; // or EXTRA_HALFBRITE
- }
- }
- #endif
-
- return iff;
-
- iffdone:
- if (iff) freeIFFHandle(iff);
- return NULL;
- }
-
-
- //===========================================================================
- // FREEIFFHANDLE -- ref: loadilbmScreen(), loadilbmBitMap(), getilbminfo()
- // Free the IFF Handle allocated by getilbminfo().
- //===========================================================================
- void freeIFFHandle(struct IFFHandle *iff)
- {
- CloseIFF(iff);
- if (iff->iff_Stream) Close(iff->iff_Stream);
- FreeIFF(iff);
- }
-
-
- //===========================================================================
- // LOADBODY -- called by loadilbm()
- // Setup to load an IFF ILBM body into a bitmap. Nonzero return means error.
- // This function expects the parser to be stopped at the beginning of the
- // BODY chunk of a file. Adapted from modules/ilbmr.c
- //===========================================================================
- int loadbody(struct IFFHandle *iff, struct BitMap *bitmap,BitMapHeader *bmhd)
- {
- BYTE *buffer;
- ULONG bufsize;
- LONG err = 0;
- register struct ContextNode *cn = CurrentChunk(iff);
-
- if (!cn) return 1;
- if (cn->cn_Type != ID_ILBM || cn->cn_ID != ID_BODY) return 1;
- if (bitmap && bmhd) {
- bufsize = MaxPackedSize(RowBytes(bmhd->w)) << 4;
- if (!(buffer = AllocMem(bufsize, 0L))) return 2;
- err = loadbody2(iff, bitmap, NULL, bmhd, buffer, bufsize);
- }
- FreeMem(buffer, bufsize);
- return err;
- }
-
-
- //===========================================================================
- // LOADBODY2 -- called by loadbody()
- // Load an IFF ILBM body into a bitmap. Nonzero return means error.
- // From modules/ilbmr.c
- //===========================================================================
-
- #define MaxSrcPlanes (25)
-
- int loadbody2(struct IFFHandle *iff, struct BitMap *bitmap,
- BYTE *mask, BitMapHeader *bmhd, BYTE *buffer, ULONG bufsize)
- {
- register int iPlane, iRow, nEmpty;
- register WORD nFilled;
- WORD srcRowBytes = RowBytes(bmhd->w),
- destRowBytes = bitmap->BytesPerRow,
- destWidthBytes, // used for width check
- compression = bmhd->compression;
- LONG bufRowBytes = MaxPackedSize(srcRowBytes);
- int nRows = bmhd->h;
- struct ContextNode *cn = CurrentChunk(iff);
- UBYTE srcPlaneCnt = bmhd->nPlanes;
- BYTE *buf, *nullDest, *nullBuf, **pDest,
- *planes[MaxSrcPlanes]; // array of ptrs to planes & mask
-
- if (compression > cmpByteRun1) return 1;
- if (((struct Library *)GfxBase)->lib_Version >= 39)
- destWidthBytes = RowBytes(GetBitMapAttr(bitmap, BMA_WIDTH));
- else
- destWidthBytes = destRowBytes;
- if (srcRowBytes > destWidthBytes || bufsize < (bufRowBytes<<1)
- || srcPlaneCnt > MaxSrcPlanes) return 1;
- if (nRows > bitmap->Rows) nRows = bitmap->Rows;
-
- // Initialize array "planes" with bitmap ptrs; NULL in empty slots.
-
- for (iPlane = 0; iPlane < bitmap->Depth; iPlane++)
- planes[iPlane] = (BYTE *)bitmap->Planes[iPlane];
- while (iPlane < MaxSrcPlanes) planes[iPlane++] = NULL;
-
- // copy any mask plane ptr into corresponding "planes" slot.
-
- if (bmhd->masking == mskHasMask)
- planes[srcPlaneCnt++] = mask ? mask : NULL;
-
- // Set up a sink for dummy destination of rows from unwanted planes
-
- nullDest = buffer;
- buffer += srcRowBytes;
- bufsize -= srcRowBytes;
-
- // Read the BODY contents into bitmap.
- // De-interleave planes, decompress rows.
- // MODIFIES: Last iteration modifies bufsize.
-
- buf = buffer + bufsize; // buffer is currently empty
- for (iRow = nRows; iRow > 0; iRow--) {
- #ifdef TIMECHECK
- if (!(iRow%(40/srcPlaneCnt))) check_for_switch(); // do it every few rows
- #endif
- for (iPlane = 0; iPlane < srcPlaneCnt; iPlane++) {
- pDest = &planes[iPlane];
- if (!(*pDest)) { // establish sink for any unwanted plane
- nullBuf = nullDest;
- pDest = &nullBuf;
- }
- // read in at least enough bytes to uncompress next row
- nEmpty = buf - buffer; // size of empty part of buffer
- nFilled = bufsize - nEmpty; // this part has data
- if (nFilled < bufRowBytes) {
- CopyMem(buf, buffer, nFilled);
- if (nEmpty > ChunkMoreBytes(cn)) { // not enough left to fill buffer
- nEmpty = ChunkMoreBytes(cn);
- bufsize = nFilled + nEmpty;
- }
- if (ReadChunkBytes(iff, &buffer[nFilled], nEmpty) < nEmpty) return 1;
-
- buf = buffer;
- nFilled = bufsize;
- // nEmpty = 0; // dead assignment
- }
- // copy uncompressed row to destination plane
- if (compression == cmpNone) {
- if (nFilled < srcRowBytes) return 2;
- CopyMem(buf, *pDest, srcRowBytes);
- buf += srcRowBytes;
- *pDest += destRowBytes;
- }
- else { // decompress row to destination plane
- if (unpackrow(&buf, pDest, nFilled, srcRowBytes))
- return 2;
- else
- *pDest += (destRowBytes - srcRowBytes);
- }
- }
- }
- return 0;
- }
-
-
- //===========================================================================
- // UNPACKROW -- called by loadbody2()
- // Given pointers to pointer variables, unpack one row, updating the source
- // and destination pointers until it produces dstBytes bytes.
- // From modules/unpacker.c
- //===========================================================================
- BOOL unpackrow(BYTE **pSource, BYTE **pDest, WORD srcBytes0, WORD dstBytes0)
- {
- register BYTE *source = *pSource;
- register BYTE *dest = *pDest;
- register WORD n;
- register WORD srcBytes = srcBytes0, dstBytes = dstBytes0;
- register BYTE c;
- BOOL error = TRUE; // assume error until we make it through the loop
- WORD minus128 = -128; // get the compiler to generate a CMP.W
-
- while (dstBytes > 0) {
- if (--srcBytes < 0) goto errorexit;
- n = *source++;
- if (n >= 0) {
- ++n;
- if ((srcBytes -= n) < 0) goto errorexit;
- if ((dstBytes -= n) < 0) goto errorexit;
- do { *dest++ = *source++; } while (--n > 0);
- }
- else if (n != minus128) {
- n = 1 - n;
- if (--srcBytes < 0) goto errorexit;
- if ((dstBytes -= n) < 0) goto errorexit;
- c = *source++;
- do { *dest++ = c; } while (--n > 0);
- }
- }
- error = FALSE; // success!
-
- errorexit:
- *pSource = source; *pDest = dest;
- return error;
- }
-
-
- #ifdef USE_GETBM // ignore getBitMap() if USE_GETBM not defined
- //=========================================================================
- // GETBITMAP
- // Allocate a bitmap according to the dimensions provided, clear it if
- // clear is nonzero, and return a pointer to the bitmap. NULL is returned
- // if the bitmap couldn't be created.
- // This function has nothing to do with modules/getbitmap.c in the RKM.
- //=========================================================================
- struct BitMap *getBitMap(int wide, int high, int deep, short clear)
- {
- register short i;
- struct BitMap *bitmap;
- if (!(bitmap = (struct BitMap *)
- AllocMem(sizeof(struct BitMap), MEMF_PUBLIC|MEMF_CLEAR)))
- goto bitmaperr;
- InitBitMap(bitmap, deep, wide, high);
- for (i = 0; i < deep; i++) {
- if (!(bitmap->Planes[i] = (PLANEPTR)AllocRaster(wide, high)))
- goto bitmaperr;
- if (clear) BltClear(bitmap->Planes[i], RASSIZE(wide, high), 0);
- }
- return bitmap;
-
- bitmaperr:
- freeBitMap(bitmap);
- return NULL;
- }
- #endif
-
-
- #ifdef USE_FREEBM // ignore freeBitMap() if USE_FREEBM not defined
- //==========================================================================
- // FREEBITMAP
- // Deallocate a bitmap structure, with all its bitplanes.
- //==========================================================================
- void freeBitMap(struct BitMap *bm)
- {
- short j;
- if (bm) {
- for (j = 0; j < bm->Depth; j++)
- if (bm->Planes[j])
- FreeRaster(bm->Planes[j], bm->BytesPerRow << 3, bm->Rows);
- FreeMem(bm, sizeof(struct BitMap));
- }
- }
- #endif
-